// $Id: ptr.cpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#include <boost/test/unit_test.hpp>
#include <xpcom/proxy/ptr.hpp>
#include "interface_def.hpp"

namespace xpcom {
namespace {

void do_in_impl_1(IA* p)
{
    BOOST_CHECK(!p);
}

void do_in_1(noref_ptr<IA> p)
{
    do_in_impl_1(proxy::ptr_in(p));
}

void do_in_impl_2(IA* p)
{
    BOOST_CHECK(p);
    BOOST_CHECK(p->getN() == 9);
}

void do_in_2(noref_ptr<IA> p)
{
    do_in_impl_2(proxy::ptr_in(p));
}

void do_out_impl_1(IBase** pp)
{
    BOOST_CHECK(*pp == 0);
    IBase* p = X_make_instance();
    p->add_ref();
    p->setN(8);
    *pp = p;
}

void do_out_1(ref_ptr<IBase>& p)
{
    do_out_impl_1(proxy::ptr_out(p));
}

void do_out_impl_2(IBase** pp)
{
    BOOST_CHECK(*pp == 0);
    *pp = 0;
}

void do_out_2(ref_ptr<IBase>& p)
{
    do_out_impl_2(proxy::ptr_out(p));
}

void do_inout_impl_1(IBase** pp)
{
    BOOST_CHECK(*pp == 0);
    IBase* p = X_make_instance();
    p->add_ref();
    p->setN(30);
    *pp = p;
}

void do_inout_1(ref_ptr<IBase>& p)
{
    do_inout_impl_1(proxy::ptr_inout(p));
}

void do_inout_impl_2(IBase** pp)
{
    BOOST_CHECK(*pp != 0);
    BOOST_CHECK_EQUAL((*pp)->getN(), 40);
    (*pp)->setN(50);
}

void do_inout_2(ref_ptr<IBase>& p)
{
    do_inout_impl_2(proxy::ptr_inout(p));
}

void do_inout_impl_3(IBase** pp)
{
    BOOST_CHECK(*pp != 0);
    BOOST_CHECK_EQUAL((*pp)->getN(), 60);

    (*pp)->release();
    *pp = 0;

    IBase* p = X_make_instance();
    p->add_ref();
    p->setN(70);
    *pp = p;
}

void do_inout_3(ref_ptr<IBase>& p)
{
    do_inout_impl_3(proxy::ptr_inout(p));
}

void do_inout_impl_4(IBase** pp)
{
    BOOST_CHECK(*pp != 0);
    BOOST_CHECK_EQUAL((*pp)->getN(), 80);

    (*pp)->release();
    *pp = 0;
}

void do_inout_4(ref_ptr<IBase>& p)
{
    do_inout_impl_4(proxy::ptr_inout(p));
}

}
}

BOOST_AUTO_TEST_CASE(test_ptr_in)
{
    using namespace xpcom;

    X_count_guard g;
    X_count(0);
    {
        noref_ptr<IA> p;
        do_in_1(p);

        ref_ptr<IA> p2(static_cast<IA*>(X_make_instance()));
        p2->setN(9);
        do_in_2(p2);

        BOOST_CHECK_EQUAL(X_count(), 1);
    }
    BOOST_CHECK_EQUAL(X_count(), 0);
}

BOOST_AUTO_TEST_CASE(test_ptr_out)
{
    using namespace xpcom;

    X_count_guard g;
    X_count(0);
    {
        ref_ptr<IBase> p;

        do_out_1(p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p);
        BOOST_CHECK_EQUAL(p->getN(), 8);

        do_out_2(p);
        BOOST_CHECK_EQUAL(X_count(), 0);
        BOOST_CHECK(!p);
    }
    BOOST_CHECK_EQUAL(X_count(), 0);
}

BOOST_AUTO_TEST_CASE(test_ptr_inout)
{
    using namespace xpcom;

    X_count_guard g;
    X_count(0);
    {
        ref_ptr<IBase> p;

        do_inout_1(p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p);
        BOOST_CHECK_EQUAL(p->getN(), 30);

        p->setN(40);
        do_inout_2(p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p);
        BOOST_CHECK_EQUAL(p->getN(), 50);

        p->setN(60);
        do_inout_3(p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p);
        BOOST_CHECK_EQUAL(p->getN(), 70);

        p->setN(80);
        do_inout_4(p);
        BOOST_CHECK_EQUAL(X_count(), 0);
        BOOST_CHECK(!p);
    }
    BOOST_CHECK_EQUAL(X_count(), 0);
}
